using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Web.Mvc;
using Mayando.ProviderModel.PhotoProviders;
using Mayando.Web.Extensions;
using Mayando.Web.Infrastructure;
using Mayando.Web.Models;
using Mayando.Web.Providers;
using Mayando.Web.ViewModels;

namespace Mayando.Web.Controllers
{
    [Description("Handles actions that have to do with the photo provider.")]
    public class PhotoProviderController : ProviderControllerBase
    {
        #region Constants

        public const string ControllerName = "photoprovider";

        #endregion

        #region Actions

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        [Description("Shows the Photo Provider administration page.")]
        public ActionResult Index()
        {
            using (var repository = GetRepository())
            {
                // Get provider info.
                var availableProviders = GetProviderList(PhotoProviderFactory.GetAvailableProviders(), this.SiteData.Settings.PhotoProviderGuid);
                var providerInfo = PhotoProviderFactory.GetProviderInfo(this.SiteData.Settings.PhotoProviderGuid);

                // Get provider status.
                PhotoProviderStatus providerStatus = null;
                var provider = PhotoProviderFactory.CreateProvider(this.SiteData.Settings.PhotoProviderGuid);
                if (provider != null)
                {
                    try
                    {
                        providerStatus = provider.GetStatus();
                    }
                    catch (Exception exc)
                    {
                        Logger.LogException(exc);
                        providerStatus = new PhotoProviderStatus(GetStatusDescriptionForException(exc), true, true);
                    }
                }
                if (providerStatus == null)
                {
                    providerStatus = new PhotoProviderStatus(null, true, true);
                }

                // Get provider settings.
                var settings = repository.GetSettings(SettingsScope.PhotoProvider);
                var settingsViewModel = SettingsController.GetSettingsViewModel(settings, this.ControllerContext.HttpContext);

                // Create full view model with all details.
                var syncStatus = new SynchronizationStatus(SiteData.Settings.PhotoProviderLastSyncTime, SiteData.Settings.PhotoProviderLastSyncStatus, SiteData.Settings.PhotoProviderLastSyncNewPhotos, SiteData.Settings.PhotoProviderLastSyncNewComments, SiteData.Settings.PhotoProviderLastSyncWasSimulation);
                var proposedStartTime = (syncStatus.LastSyncTime.HasValue ? syncStatus.LastSyncTime.Value : DateTimeOffset.UtcNow);
                var model = new PhotoProviderViewModel(availableProviders, providerInfo, providerStatus, syncStatus, settingsViewModel, proposedStartTime);
                return View(ViewName.Index, model);
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult SelectProvider(string selectedProvider)
        {
            if (!string.Equals(selectedProvider, this.SiteData.Settings.PhotoProviderGuid, StringComparison.OrdinalIgnoreCase))
            {
                using (var repository = GetRepository(true))
                {
                    this.SiteData.Settings.PhotoProviderGuid = selectedProvider;
                    repository.SaveSettingValues(SettingsScope.Application, this.SiteData.Settings.GetChangedSettings());
                    ResetProvider(repository, this.SiteData);
                    repository.CommitChanges();
                    SetPageFlash("The photo provider was changed.");
                }
            }
            return RedirectToAction(ActionName.Index);
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Synchronize(DateTimeOffset syncStartTime, string tagList, bool simulate)
        {
            var provider = PhotoProviderFactory.CreateProvider(this.SiteData.Settings.PhotoProviderGuid);
            if (provider != null)
            {
                // Synchronize.
                var tags = Converter.ToTags(tagList);
                SynchronizationResult result = null;
                IList<string> existingExternalPhotoIds;
                IList<string> existingExternalCommentIds;

                using (var repository = GetRepository())
                {
                    existingExternalPhotoIds = repository.GetExternalPhotoIds();
                    existingExternalCommentIds = repository.GetExternalCommentIds();
                }

                try
                {
                    result = provider.Synchronize(new SynchronizationRequest(existingExternalPhotoIds, existingExternalCommentIds, syncStartTime, tags));
                }
                catch (Exception exc)
                {
                    Logger.LogException(exc);
                    result = new SynchronizationResult(false, GetStatusDescriptionForException(exc), null);
                }
                if (result == null)
                {
                    result = new SynchronizationResult(false, null, null);
                }

                // Update database.
                using (var repository = GetRepository(true))
                {
                    var lastSyncTime = this.SiteData.Settings.PhotoProviderLastSyncTime;
                    var lastSyncStatus = result.StatusDescriptionHtml;
                    int? lastSyncNewPhotos = null;
                    int? lastSyncNewComments = null;
                    if (!simulate)
                    {
                        if (result.Success)
                        {
                            if (result.PhotosToAdd != null)
                            {
                                repository.AddPhotos(result.PhotosToAdd);
                                lastSyncNewPhotos = result.PhotosToAdd.Count;
                            }
                            else
                            {
                                lastSyncNewPhotos = 0;
                            }
                            if (result.CommentsToAdd != null)
                            {
                                repository.AddComments(result.CommentsToAdd);
                                lastSyncNewComments = result.CommentsToAdd.Count;
                            }
                            else
                            {
                                lastSyncNewComments = 0;
                            }
                            lastSyncTime = DateTimeOffset.UtcNow;
                        }
                    }
                    SaveSynchronizationResults(repository, this.SiteData, lastSyncTime, lastSyncStatus, lastSyncNewPhotos, lastSyncNewComments, simulate);
                    repository.CommitChanges();
                }

                // Finish.
                if (result.Success)
                {
                    SetPageFlash("The photo provider successfully completed synchronization.");
                }
                else
                {
                    SetPageFlash("The photo provider failed to complete synchronization.");
                }
            }
            return RedirectToAction(ActionName.Index);
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Reset()
        {
            using (var repository = GetRepository(true))
            {
                ResetProvider(repository, this.SiteData);
                repository.CommitChanges();
                SetPageFlash("The photo provider was reset.");
                return RedirectToAction(ActionName.Index);
            }
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Edit(IDictionary<string, string> settings)
        {
            using (var repository = GetRepository(true))
            {
                repository.SaveSettingValues(SettingsScope.PhotoProvider, settings);
                repository.CommitChanges();
                SetPageFlash("The photo provider settings were saved.");
                return RedirectToAction(ActionName.Index);
            }
        }

        #endregion

        #region Helper Methods

        private static void ResetProvider(MayandoRepository repository, SiteData siteData)
        {
            var provider = PhotoProviderFactory.CreateProvider(siteData.Settings.PhotoProviderGuid);
            if (provider != null)
            {
                provider.Reset();
            }
            SaveSynchronizationResults(repository, siteData, null, null, null, null, null);
        }

        private static void SaveSynchronizationResults(MayandoRepository repository, SiteData siteData, DateTimeOffset? lastSyncTime, string lastSyncStatus, int? lastSyncNewPhotos, int? lastSyncNewComments, bool? lastSyncWasSimulation)
        {
            siteData.Settings.PhotoProviderLastSyncTime = lastSyncTime;
            siteData.Settings.PhotoProviderLastSyncNewPhotos = lastSyncNewPhotos;
            siteData.Settings.PhotoProviderLastSyncNewComments = lastSyncNewComments;
            siteData.Settings.PhotoProviderLastSyncWasSimulation = lastSyncWasSimulation;
            siteData.Settings.PhotoProviderLastSyncStatus = lastSyncStatus;
            repository.SaveSettingValues(SettingsScope.Application, siteData.Settings.GetChangedSettings());
        }

        #endregion
    }
}